package com.sunop.discussion.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunop.api.client.user.UserClient;
import com.sunop.api.model.UserBaseDTO;
import com.sunop.discussion.mapper.DiscussionMapper;
import com.sunop.discussion.model.*;
import com.sunop.discussion.service.DiscussionService;
import com.sunop.panticommon.entity.Result;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.sunop.panticommon.entity.PageResult;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @since 2025-03-22
 */
@Service
@AllArgsConstructor
@Slf4j
public class DiscussionServiceImpl extends ServiceImpl<DiscussionMapper, Discussion> implements DiscussionService {

    private final UserClient userClient;
    private final DiscussionMapper discussionMapper;
    private final RedisTemplate redisTemplate;
    private final UserClient roleClient;


    @Override
    public Result sendComment(DiscussionSendDTO discussionSendDTO) {
        Discussion discussion = new Discussion();
        BeanUtil.copyProperties(discussionSendDTO, discussion);
        int uid = StpUtil.getLoginIdAsInt();
        try {
            UserBaseDTO userBaseDTO = userClient.getUserBaseDTO(uid);
            BeanUtil.copyProperties(userBaseDTO, discussion);
            discussionMapper.insert(discussion);
            // 检查是否是当天第一次评论
            String redisKey = "discussion:" + uid + ":" + LocalDate.now();
            if (!redisTemplate.hasKey(redisKey)) {
                // 是第一次评论，加分
                roleClient.updateUserPoints(uid, 1); // 假设有一个方法用于更新用户积分

                // 设置 Redis 记录，过期时间为 22 小时
                redisTemplate.opsForValue().set(redisKey, "1", 22, TimeUnit.HOURS);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return Result.success(null, "评论成功");

    }

    @Override
    public PageResult pageQuery(DiscussionPageQueryDTO discussionPageQueryDTO) {
        parameterCheck(discussionPageQueryDTO);
        PageHelper.startPage(discussionPageQueryDTO.getPageNum(), discussionPageQueryDTO.getPageSize());
        Page<Discussion> page = discussionMapper.pageQuery(discussionPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    @Override
    public Result delById(Integer id) {
        if (discussionMapper.selectCidById(id) != StpUtil.getLoginIdAsInt())
            return Result.error("删除失败，您不是该评论的作者");
        discussionMapper.deleteById(id);
        return Result.success(null, "删除成功");
    }

    @Override
    public Result sendReply(DiscussionReplyDTO discussionSendDTO) {
        DiscussionReplyPO discussionReplyPO = new DiscussionReplyPO();
        BeanUtil.copyProperties(discussionSendDTO, discussionReplyPO);
        int uid = StpUtil.getLoginIdAsInt();
        try {
            UserBaseDTO userBaseDTO = userClient.getUserBaseDTO(uid);
            BeanUtil.copyProperties(userBaseDTO, discussionReplyPO);
            discussionMapper.insertReply(discussionReplyPO);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return Result.success(null, "回复成功");
    }

    @Override
    public PageResult replyPageQuery(DiscussionPageQueryDTO discussionPageQueryDTO, int cid) {
        parameterCheck(discussionPageQueryDTO);
        PageHelper.startPage(discussionPageQueryDTO.getPageNum(), discussionPageQueryDTO.getPageSize());
        Page<DiscussionReplyPO> page = discussionMapper.replyPageQuery(cid, discussionPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    @Override
    public Result delReplyById(Integer id) {
        if (discussionMapper.selectReplyCidById(id) != StpUtil.getLoginIdAsInt())
            return Result.error("删除失败，您不是该评论的作者");
        discussionMapper.deleteReplyById(id);
        return Result.success(null, "删除成功");
    }

    @Override
    public Result discussionLike(Integer discussionId) {
        try {
            redisTemplate.opsForSet().add("like:" + "discussion:" + discussionId + ":user:" + StpUtil.getLoginIdAsInt(), discussionId);
            redisTemplate.opsForValue().increment("like:" + "discussion:" + discussionId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return Result.success(null, "点赞成功");
    }

    @Override
    public Result discussionUnlike(Integer discussionId) {
        try {
            redisTemplate.opsForSet().remove("like:" + "discussion:" + discussionId + ":user:" + StpUtil.getLoginIdAsInt(), discussionId);
            redisTemplate.opsForValue().decrement("like:" + "discussion:" + discussionId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return Result.success(null, "取消点赞成功");
    }

    @Override
    public Result collectDiscussion(Integer discussionId) {
        try {
            // 获取当前用户 ID
            int userId = StpUtil.getLoginIdAsInt();
            // 将讨论帖 ID 添加到用户的有序集合中，Score 为当前时间戳
            double score = System.currentTimeMillis();
            redisTemplate.opsForZSet().add("user:collect:" + userId, discussionId, score);
            return Result.success(null, "收藏成功");
        } catch (Exception e) {
            throw new RuntimeException("收藏失败", e);
        }
    }

    @Override
    public Result uncollectDiscussion(Integer discussionId) {
        try {
            // 获取当前用户 ID
            int userId = StpUtil.getLoginIdAsInt();
            // 将讨论帖 ID 从用户的有序集合中移除
            redisTemplate.opsForZSet().remove("user:collect:" + userId, discussionId);
            return Result.success(null, "取消收藏成功");
        } catch (Exception e) {
            throw new RuntimeException("取消收藏失败", e);
        }
    }

    // 获取收藏的讨论帖列表
    @Override
    public Result getCollectedDiscussions(int page, int size, boolean reverseOrder) {
        try {
            // 获取当前用户 ID
            int userId = StpUtil.getLoginIdAsInt();
            // 计算分页的起始和结束位置
            long start = (page - 1) * size;
            long end = start + size - 1;
            // 根据排序规则获取分页数据
            Set<Integer> discussionIds;
            if (reverseOrder) {
                // 倒序：按 Score 从大到小排序
                discussionIds = redisTemplate.opsForZSet().reverseRange("user:collect:" + userId, start, end);
            } else {
                // 正序：按 Score 从小到大排序
                discussionIds = redisTemplate.opsForZSet().range("user:collect:" + userId, start, end);
            }
            // 返回收藏的讨论帖 ID 列表
            return Result.success(discussionIds, "获取收藏列表成功");
        } catch (Exception e) {
            throw new RuntimeException("获取收藏列表失败", e);
        }
    }

    @Override
    public long getCollectedCount() {
        try {
            // 获取当前用户 ID
            int userId = StpUtil.getLoginIdAsInt();
            // 获取用户的有序集合大小
            return redisTemplate.opsForZSet().size("user:collect:" + userId);
        } catch (Exception e) {
            throw new RuntimeException("获取收藏总数失败", e);
        }
    }

    @Override
    public boolean isDiscussionCollected(Integer discussionId) {
        try {
            // 获取当前用户 ID
            int userId = StpUtil.getLoginIdAsInt();
            // 检查讨论帖 ID 是否在用户的有序集合中
            return redisTemplate.opsForZSet().score("user:collect:" + userId, discussionId) != null;
        } catch (Exception e) {
            throw new RuntimeException("检查收藏状态失败", e);
        }
    }

    private static void parameterCheck(DiscussionPageQueryDTO discussionPageQueryDTO) {
        if (discussionPageQueryDTO.getPageNum() < 1 || discussionPageQueryDTO.getPageSize() < 1) {
            throw new IllegalArgumentException("Invalid pageNum or pageSize value");
        }
        List<String> allowedSortBy = Arrays.asList("id", "comment_num", "submit_num", "pass_num", "create_time");
        List<String> allowedOrderBy = Arrays.asList("asc", "desc");
        if (!allowedSortBy.contains(discussionPageQueryDTO.getSortBy())) {
            throw new IllegalArgumentException("Invalid sortBy value: " + discussionPageQueryDTO.getSortBy());
        }
        if (!allowedOrderBy.contains(discussionPageQueryDTO.getOrderBy())) {
            throw new IllegalArgumentException("Invalid orderBy value: " + discussionPageQueryDTO.getOrderBy());
        }
    }
}
